import Settings, {
  ISettings,
  SettingsType,
  UserPreferences,
  SystemConfig,
  IntegrationConfig,
  NotificationChannel
} from '@database/models/Settings';
import logger from '@utils/logger';

/**
 * Settings Service
 */
class SettingsService {
  /**
   * Get user settings
   */
  async getUserSettings(userId: string): Promise<any> {
    try {
      const settings = await Settings.find({
        type: SettingsType.USER,
        userId
      });

      // Convert array to object
      const settingsObj: any = {};
      settings.forEach(setting => {
        settingsObj[setting.key] = setting.value;
      });

      return settingsObj;
    } catch (error) {
      logger.error('Failed to get user settings:', error as Error);
      throw error;
    }
  }

  /**
   * Get user preferences (merged with defaults)
   */
  async getUserPreferences(userId: string): Promise<UserPreferences> {
    try {
      const defaultPreferences: UserPreferences = {
        theme: 'light',
        language: 'auto',
        timezone: 'UTC',
        dateFormat: 'YYYY-MM-DD',
        timeFormat: '24h',
        notifications: {
          email: true,
          browser: true,
          sound: false
        },
        dashboard: {
          layout: ['overview', 'alerts', 'tickets', 'performance'],
          defaultView: 'overview'
        }
      };

      const settings = await this.getUserSettings(userId);
      const preferences = settings.preferences || {};

      return {
        ...defaultPreferences,
        ...preferences
      };
    } catch (error) {
      logger.error('Failed to get user preferences:', error as Error);
      throw error;
    }
  }

  /**
   * Update user settings
   */
  async updateUserSettings(userId: string, key: string, value: any, updatedBy?: string): Promise<ISettings> {
    try {
      return await Settings.findOneAndUpdate(
        { type: SettingsType.USER, userId, key },
        {
          value,
          'metadata.updatedBy': updatedBy || userId
        },
        { upsert: true, new: true }
      );
    } catch (error) {
      logger.error('Failed to update user settings:', error as Error);
      throw error;
    }
  }

  /**
   * Update user preferences
   */
  async updateUserPreferences(userId: string, preferences: Partial<UserPreferences>, updatedBy?: string): Promise<ISettings> {
    try {
      const currentPrefs = await this.getUserPreferences(userId);
      const mergedPrefs = {
        ...currentPrefs,
        ...preferences
      };

      return await this.updateUserSettings(userId, 'preferences', mergedPrefs, updatedBy);
    } catch (error) {
      logger.error('Failed to update user preferences:', error as Error);
      throw error;
    }
  }

  /**
   * Get system settings
   */
  async getSystemSettings(): Promise<any> {
    try {
      const settings = await Settings.find({
        type: SettingsType.SYSTEM
      });

      const settingsObj: any = {};
      settings.forEach(setting => {
        settingsObj[setting.key] = setting.value;
      });

      return settingsObj;
    } catch (error) {
      logger.error('Failed to get system settings:', error as Error);
      throw error;
    }
  }

  /**
   * Get system config (merged with defaults)
   */
  async getSystemConfig(): Promise<SystemConfig> {
    try {
      const defaultConfig: SystemConfig = {
        siteName: 'DevOps SmartBot',
        siteUrl: 'http://localhost:3000',
        adminEmail: 'admin@devops.com',
        alertRetentionDays: 90,
        ticketRetentionDays: 365,
        enableAIAnalysis: true,
        enableAutoCreateTicket: true,
        slaEnabled: true,
        slaPolicies: {
          critical: 4,   // 4 hours
          high: 8,       // 8 hours
          medium: 24,    // 24 hours
          low: 48        // 48 hours
        },
        maintenanceMode: false,
        maintenanceMessage: ''
      };

      const settings = await this.getSystemSettings();
      const config = settings.config || {};

      return {
        ...defaultConfig,
        ...config
      };
    } catch (error) {
      logger.error('Failed to get system config:', error as Error);
      throw error;
    }
  }

  /**
   * Update system settings
   */
  async updateSystemSettings(key: string, value: any, updatedBy?: string): Promise<ISettings> {
    try {
      return await Settings.findOneAndUpdate(
        { type: SettingsType.SYSTEM, key },
        {
          value,
          'metadata.updatedBy': updatedBy || 'system'
        },
        { upsert: true, new: true }
      );
    } catch (error) {
      logger.error('Failed to update system settings:', error as Error);
      throw error;
    }
  }

  /**
   * Update system config
   */
  async updateSystemConfig(config: Partial<SystemConfig>, updatedBy?: string): Promise<ISettings> {
    try {
      const currentConfig = await this.getSystemConfig();
      const mergedConfig = {
        ...currentConfig,
        ...config
      };

      return await this.updateSystemSettings('config', mergedConfig, updatedBy);
    } catch (error) {
      logger.error('Failed to update system config:', error as Error);
      throw error;
    }
  }

  /**
   * Get integration settings
   */
  async getIntegrationSettings(): Promise<any> {
    try {
      const settings = await Settings.find({
        type: SettingsType.INTEGRATION
      });

      const settingsObj: any = {};
      settings.forEach(setting => {
        settingsObj[setting.key] = setting.value;
      });

      return settingsObj;
    } catch (error) {
      logger.error('Failed to get integration settings:', error as Error);
      throw error;
    }
  }

  /**
   * Get integration config (merged with defaults)
   */
  async getIntegrationConfig(): Promise<IntegrationConfig> {
    try {
      const defaultConfig: IntegrationConfig = {
        prometheus: {
          url: 'http://prometheus:9090',
          enabled: true
        },
        grafana: {
          url: 'http://grafana:3000',
          enabled: true
        },
        alertmanager: {
          url: 'http://alertmanager:9093',
          enabled: true
        },
        openai: {
          apiKey: process.env.OPENAI_API_KEY || '',
          model: 'gpt-4',
          enabled: true
        }
      };

      const settings = await this.getIntegrationSettings();

      return {
        prometheus: { ...defaultConfig.prometheus, ...(settings.prometheus || {}) },
        grafana: { ...defaultConfig.grafana, ...(settings.grafana || {}) },
        alertmanager: { ...defaultConfig.alertmanager, ...(settings.alertmanager || {}) },
        openai: { ...defaultConfig.openai, ...(settings.openai || {}) }
      };
    } catch (error) {
      logger.error('Failed to get integration config:', error as Error);
      throw error;
    }
  }

  /**
   * Update integration settings
   */
  async updateIntegrationSettings(key: string, value: any, updatedBy?: string): Promise<ISettings> {
    try {
      return await Settings.findOneAndUpdate(
        { type: SettingsType.INTEGRATION, key },
        {
          value,
          'metadata.updatedBy': updatedBy || 'system'
        },
        { upsert: true, new: true }
      );
    } catch (error) {
      logger.error('Failed to update integration settings:', error as Error);
      throw error;
    }
  }

  /**
   * Get notification channels
   */
  async getNotificationChannels(): Promise<NotificationChannel[]> {
    try {
      const setting = await Settings.findOne({
        type: SettingsType.SYSTEM,
        key: 'notificationChannels'
      });

      if (setting) {
        return setting.value as NotificationChannel[];
      }

      // Default channels
      return [
        {
          type: 'email',
          enabled: true,
          config: {
            smtp: {
              host: process.env.SMTP_HOST || 'smtp.gmail.com',
              port: parseInt(process.env.SMTP_PORT || '587'),
              secure: false,
              auth: {
                user: process.env.SMTP_USER || '',
                pass: process.env.SMTP_PASS || ''
              }
            }
          }
        },
        {
          type: 'slack',
          enabled: false,
          config: {
            webhookUrl: process.env.SLACK_WEBHOOK_URL || ''
          }
        },
        {
          type: 'dingtalk',
          enabled: false,
          config: {
            webhookUrl: process.env.DINGTALK_WEBHOOK_URL || ''
          }
        },
        {
          type: 'webhook',
          enabled: false,
          config: {
            url: ''
          }
        }
      ];
    } catch (error) {
      logger.error('Failed to get notification channels:', error as Error);
      throw error;
    }
  }

  /**
   * Update notification channels
   */
  async updateNotificationChannels(channels: NotificationChannel[], updatedBy?: string): Promise<ISettings> {
    try {
      return await this.updateSystemSettings('notificationChannels', channels, updatedBy);
    } catch (error) {
      logger.error('Failed to update notification channels:', error as Error);
      throw error;
    }
  }

  /**
   * Delete setting
   */
  async deleteSetting(type: SettingsType, key: string, userId?: string): Promise<boolean> {
    try {
      const filter: any = { type, key };
      if (userId) filter.userId = userId;

      const result = await Settings.deleteOne(filter);
      return result.deletedCount > 0;
    } catch (error) {
      logger.error('Failed to delete setting:', error as Error);
      throw error;
    }
  }

  /**
   * Reset to defaults
   */
  async resetToDefaults(type: SettingsType, userId?: string): Promise<boolean> {
    try {
      const filter: any = { type };
      if (userId) filter.userId = userId;

      const result = await Settings.deleteMany(filter);
      return result.deletedCount > 0;
    } catch (error) {
      logger.error('Failed to reset settings:', error as Error);
      throw error;
    }
  }
}

export default new SettingsService();
